#pragma once
#include "requestor.hpp"
#include "../common/net.hpp"

namespace qiangsir
{
    namespace client
    {
        class TopicManange
        {
        public:
            using ptr = std::shared_ptr<TopicManange>;
            using SubCallBack = std::function<void(const std::string, const std::string)>;
            TopicManange(const Requestor::ptr& requestor) : _requestor(requestor) {}
            bool create(const BaseConnection::ptr &conn, const std::string &key)
            {
                return commonTopicRequest(conn, key, TopicOptype::TOPIC_CREATE);
            }
            bool remove(const BaseConnection::ptr &conn, const std::string &key)
            {
                return commonTopicRequest(conn, key, TopicOptype::TOPIC_REMOVE);
            }
            bool subsribe(const BaseConnection::ptr &conn, const std::string &key, const SubCallBack &cb)
            {
                addSubsribe(key, cb);
                bool ret = commonTopicRequest(conn, key, TopicOptype::TOPIC_SUBSCRIBE);
                if (ret == false)
                {
                    delSubsribe(key);
                    return false;
                }
                return true;
            }
            bool cancel(const BaseConnection::ptr &conn, const std::string &key)
            {
                delSubsribe(key);
                return commonTopicRequest(conn, key, TopicOptype::TOPIC_CANCEL);
            }
            bool publish(const BaseConnection::ptr &conn, const std::string &key, const std::string &msg)
            {
                return commonTopicRequest(conn, key, TopicOptype::TOPIC_PUBLISH, msg);
            }
            void onPublish(const BaseConnection::ptr &conn, const TopicRequest::ptr &msg)
            {
                // 1. 从消息中取出操作类型进行判断，是否是消息请求
                auto type = msg->optype();
                if (type != TopicOptype::TOPIC_PUBLISH)
                {
                    ELOG("收到了错误类型的主题操作！");
                    return;
                }
                // 2. 取出消息主题名称，以及消息内容
                std::string topic_key = msg->topicKey();
                std::string topic_msg = msg->topicMessage();
                // 3. 通过主题名称，查找对应主题的回调处理函数，有在处理，无在报错
                auto callback = getSubsribe(topic_key);
                if (!callback)
                {
                    ELOG("收到了 %s 主题消息，但是该消息无主题处理回调！", topic_key.c_str());
                    return;
                }
                return callback(topic_key, topic_msg);
            }

        private:
            void addSubsribe(const std::string &key, const SubCallBack &cb)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _topic_callback.insert(std::make_pair(key, cb));
            }
            void delSubsribe(const std::string &key)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _topic_callback.erase(key);
            }
            const SubCallBack getSubsribe(const std::string &key)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _topic_callback.find(key);
                if (it == _topic_callback.end())
                {
                    return SubCallBack();
                }
                return it->second;
            }
            bool commonTopicRequest(const BaseConnection::ptr &conn, const std::string &key,
                                    TopicOptype optype, const std::string &msg = "")
            {
                auto req_msg = BaseMessageFactory::create<TopicRequest>();
                req_msg->setId(UUID::uuid());
                req_msg->setType(MType::REQ_TOPIC);
                req_msg->setOptype(optype);
                req_msg->setTopicKey(key);
                if (req_msg->optype() == TopicOptype::TOPIC_PUBLISH)
                {
                    req_msg->setMessage(msg);
                }
                BaseMessage::ptr resp_msg;
                // 向服务端发送请求
                bool ret = _requestor->send(conn, req_msg, resp_msg);
                if (ret == false)
                {
                    ELOG("主题操作请求失败！");
                    return false;
                }
                auto rsp_msg = std::dynamic_pointer_cast<TopicResponse>(resp_msg);
                if (rsp_msg == nullptr)
                {
                    ELOG("主题操作响应，向下类型转换失败！");
                    return false;
                }
                if (rsp_msg->rcode() != RCode::RCODE_OK)
                {
                    ELOG("主题操作请求出错：%s", errReason(rsp_msg->rcode()).c_str());
                    return false;
                }
                return true;
            }
            std::mutex _mutex;
            std::unordered_map<std::string, SubCallBack> _topic_callback;
            Requestor::ptr _requestor;
        };
    }
}